package com.cskaoyan.javase.oop2._1extends._8initialization._1basic;

/**
 * 我们通过一个引例，练习来讲解这个问题：
 * 创建一个Person类，有name属性和eat方法
 * 创建一个Star类，有stageName属性和sing方法
 * Star类要继承Person类
 * 创建Star类对象，画出这个过程的内存图，描述子类对象初始化的过程。
 *
 * 结论:
 *      1.触发子类类加载,会优先类加载父类.,"先父后子"
 *          从方法的栈帧上来说,是父类的clinit方法栈帧先进栈,子类方法栈帧后进栈.
 *          如果有多个父类,那就从最顶层父类开始向下进行类加载.
 *          这也是一个类加载的时机: 触发子类类加载,先类加载父类
 *
 *      2.开始创建对象,在堆上只会创建一个子类对象,不会创建任何父类对象
 *
 *      3.子类对象中会专门开辟一片独立的区域，用来存储父类的成员变量，而子类自身的成员仍会存储在自身对象当中。
 *          这样子类对象就被划分为了两个区域:
 *          a.父类成员的区域: 可以近似的看成一个父类对象,这片子类对象中的区域,使用super关键字指向它
 *              可以近似的看成,super指向父类对象
 *          b.子类自身成员的区域
 *
 * 接下来主要研究子类对象中,父子类成员变量的赋值顺序以及结果:
 * 首先,要明确,成员变量的默认初始化永远最先进行,所以父子类成员变量都具有默认值,然后在默认值的基础上进行其他赋值
 * 默认初始化不考虑
 *      1.除了默认初始化,其它的赋值手段的执行,是按照"先父后子"执行的
 *          包括:
 *              a.显式赋值
 *              b.构造代码块赋值
 *              c.构造器赋值
 *
 *
 *      2.成员变量赋值的"先父后子",究竟是如何保证的呢?原理是什么样的呢?(最重要)
 *      猜想: 只要保证父类构造器先于子类执行
 *          那么父类的所有赋值手段都先于子类的赋值手段
 *      通过构造代码块的先父后子执行,说明以上猜想是正确的.
 *     结论: 父子类成员变量的先父后子的赋值顺序
 *          是通过父类构造器先执行来保证的
 *
 *
 *      3.父类的构造器为什么先于子类执行?(最重要)
 *
 *      super关键字可以在构造器中使用,表示调用父类的构造器,语法:
 *          super(实参列表);
 *      (重点)
 *      在一个类中的构造器中,如果构造器第一行没有直接用this/super去调用其他构造器,那么它一定隐含语句:
 *      super();
 *      表示调用父类的无参构造器
 *      这样就能够保证父类的构造器代码先于子类执行
 *      就能够保证赋值顺序先父后子
 *
 *      这种程序员没有写任何代码,通过隐含super()的形式,来完成子类对象初始化的方式
 *      称之为"子类对象的隐式初始化"
 *      子类对象的隐式初始化是调用父类无参构造器实现的
 *
 * 4.无参构造器是不能给成员变量赋值的
 *      所以在创建子类对象时,如果希望能够给父类成员赋值,就必须调用父类的有参构造器
 *      语法: 在子类构造器第一行写
 *          super(实参列表);
 *      这种程序员直接写代码,直接指出调用父类哪个构造器的子类对象创建方式,称之为"子类对象的显式初始化"
 *
 *
 * "先父后子"的两个过程
 * 类加载的先父后子以及构造器执行的先父后子:
 *
 * 1.类加载的先父后子,实际上是类初始化的先父后子
 *      表现在方法栈帧上就是clinit方法栈帧的进栈是先父后子.
 * 类加载的时机,实际上是类初始化的时机
 *
 * 2.构造器的先父后子,实际上指的是构造器代码执行的先父后子
 *      从原理上来说,这个先父后子的实现,依赖于子类构造器第一行的super(实参)
 *      所以从方法栈帧上来说,子类的方法栈帧先进栈,
 *          父类的方法栈帧依赖于子类构造器第一行的super(实参) 后进栈
 *
 * 总之一句话,先父后子,就是父类代码先执行,子类代码后执行.
 *
 * @since 11:14
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        Star s = new Star();
        System.out.println(s.name);
        System.out.println(s.stageName);
        System.out.println("------------------");
        Star s2 = new Star("李四");
        System.out.println(s2.name);
        System.out.println(s2.stageName);
        System.out.println("--------------------");
        Star s3 = new Star("王菲", "王靖雯");
        System.out.println(s3.name);
        System.out.println(s3.stageName);
    }
}

class Person {
    String name = "张三";

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }
    static {
        System.out.println("Person类,类初始化了!");
    }

    // {
    //     System.out.println("Person构造代码块~");
    // }

    public void eat() {
        System.out.println("人是铁,饭是钢,一顿不吃很难受~");
    }
}

class Star extends Person {
    static {
        System.out.println("Star类,类初始化了!");
    }
    // {
    //     System.out.println("Star构造代码块~");
    // }

    String stageName = name + "的弟弟";

    public Star() {
        // super();
    }

    public Star(String name) {
        super(name);
    }

    public Star(String name, String stageName) {
        super(name);
        this.stageName = stageName;
    }

    public void sing() {
        System.out.println("爱的供养~");
    }


}